#pragma once

namespace my_smart_ptr
{


	template <class T>
	class shared_ptr
	{

	public:
		shared_ptr(T* ptr = nullptr)
			:_ptr(ptr)
			,_n(new int(1))
		{}

		template <class D>
		shared_ptr(T* ptr,D del)
			: _ptr(ptr)
			, _n(new int(1))
			,_del(del)
		{}

		shared_ptr(const shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			,_n(sp._n)
		{
			++*(_n);
		}

		~shared_ptr()
		{
			if (--*(_n) == 0)
			{
				_del(_ptr);
				delete _n;
			}
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

		shared_ptr<T>& operator=(const shared_ptr<T>& sp)const
		{
			if (sp._ptr != _ptr)
			{

				if (--(*_n) == 0)
				{
					_del(_ptr);
					delete _n;
				}
				_ptr = sp._ptr;
				_n = sp._n;
				*(sp._n)++;
			}
			return *this;
		}
	private:
		T* _ptr;
		int* _n;
		function<void(T*)> _del = [](T* ptr) {delete ptr; };
	};
}